package com.keba.lamp.complaint.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.Lists;
import com.keba.basic.base.service.impl.SuperServiceImpl;
import com.keba.basic.cache.lock.DistributedLock;
import com.keba.basic.context.ContextConstants;
import com.keba.basic.context.ContextUtil;
import com.keba.basic.exception.BizException;
import com.keba.basic.interfaces.echo.EchoService;
import com.keba.basic.utils.ArgumentAssert;
import com.keba.lamp.ai.strategy.ApiCallStrategy;
import com.keba.lamp.ai.vo.query.AiCallModelRequestQuery;
import com.keba.lamp.common.constant.AppendixType;
import com.keba.lamp.common.constant.BizConstant;
import com.keba.lamp.common.constant.ComplaintCaseConstant;
import com.keba.lamp.common.utils.ImageUtil;
import com.keba.lamp.complaint.entity.AccountPrepayment;
import com.keba.lamp.complaint.entity.Agent;
import com.keba.lamp.complaint.entity.Case;
import com.keba.lamp.complaint.entity.CaseLog;
import com.keba.lamp.complaint.entity.ChannelCustomer;
import com.keba.lamp.complaint.entity.ComFileRel;
import com.keba.lamp.complaint.entity.CourtArea;
import com.keba.lamp.complaint.entity.Defendant;
import com.keba.lamp.complaint.entity.EvidenceCaseRel;
import com.keba.lamp.complaint.entity.Plaintff;
import com.keba.lamp.complaint.enumeration.AgentTypeEnum;
import com.keba.lamp.complaint.enumeration.DocTemplateTypeEnum;
import com.keba.lamp.complaint.enumeration.TransferTypeEnum;
import com.keba.lamp.complaint.manager.CaseLogManager;
import com.keba.lamp.complaint.manager.CaseManager;
import com.keba.lamp.complaint.manager.ChannelCustomerManager;
import com.keba.lamp.complaint.manager.ComFileRelManager;
import com.keba.lamp.complaint.manager.EvidenceComponentCaseTypeRelManager;
import com.keba.lamp.complaint.service.AccountPrepaymentService;
import com.keba.lamp.complaint.service.AgentService;
import com.keba.lamp.complaint.service.CaseService;
import com.keba.lamp.complaint.service.CourtAreaService;
import com.keba.lamp.complaint.service.DefendantService;
import com.keba.lamp.complaint.service.DocTemplateService;
import com.keba.lamp.complaint.service.EvidenceCaseRelService;
import com.keba.lamp.complaint.service.PdfCommonService;
import com.keba.lamp.complaint.service.PlaintffService;
import com.keba.lamp.complaint.vo.param.AccountPrepaymentParamVO;
import com.keba.lamp.complaint.vo.result.AgentResultVO;
import com.keba.lamp.complaint.vo.result.AiDefendantAgentResultVO;
import com.keba.lamp.complaint.vo.result.AiDefendantResultVO;
import com.keba.lamp.complaint.vo.result.AiPlaintffAgentResultVO;
import com.keba.lamp.complaint.vo.result.AiPlaintffResultVO;
import com.keba.lamp.complaint.vo.result.CaseFileResultVO;
import com.keba.lamp.complaint.vo.result.CaseResultVO;
import com.keba.lamp.complaint.vo.result.ComplaintContentVO;
import com.keba.lamp.complaint.vo.result.DefendantResultVO;
import com.keba.lamp.complaint.vo.result.DocTemplateResultVO;
import com.keba.lamp.complaint.vo.result.EvidenceCaseRelResultVO;
import com.keba.lamp.complaint.vo.result.EvidenceResultVO;
import com.keba.lamp.complaint.vo.result.PlaintffResultVO;
import com.keba.lamp.complaint.vo.result.ShareInfoResultVO;
import com.keba.lamp.complaint.vo.save.CaseFileUploadVO;
import com.keba.lamp.complaint.vo.save.CaseFileVO;
import com.keba.lamp.complaint.vo.save.CaseSaveVO;
import com.keba.lamp.complaint.vo.save.DefendantSaveVO;
import com.keba.lamp.complaint.vo.save.EvidenceVO;
import com.keba.lamp.complaint.vo.save.PlaintffSaveVO;
import com.keba.lamp.complaint.vo.update.CaseSendEmailVO;
import com.keba.lamp.complaint.vo.update.CaseUpdateComplaintContentVO;
import com.keba.lamp.complaint.vo.update.CaseUpdateVO;
import com.keba.lamp.complaint.vo.update.DefendantUpdateVO;
import com.keba.lamp.complaint.vo.update.PlaintffUpdateVO;
import com.keba.lamp.file.entity.File;
import com.keba.lamp.file.enumeration.FileStorageType;
import com.keba.lamp.file.service.AppendixService;
import com.keba.lamp.file.service.FileService;
import com.keba.lamp.file.strategy.FileContext;
import com.keba.lamp.file.vo.param.FileUploadVO;
import com.keba.lamp.file.vo.result.FileResultVO;
import com.keba.lamp.model.constant.EchoDictType;
import com.keba.lamp.model.entity.system.SysUser;
import com.keba.lamp.model.enumeration.StateEnum;
import com.keba.lamp.model.enumeration.base.FileType;
import com.keba.lamp.model.enumeration.complaint.AiFileType;
import com.keba.lamp.model.vo.result.AppendixResultVO;
import com.keba.lamp.model.vo.save.AppendixSaveVO;
import com.keba.lamp.msg.biz.MsgBiz;
import com.keba.lamp.msg.vo.save.ExtendMsgRecipientSaveVO;
import com.keba.lamp.msg.vo.update.ExtendMsgSendVO;
import com.keba.lamp.system.entity.system.DefArea;
import com.keba.lamp.system.entity.tenant.DefUser;
import com.keba.lamp.system.manager.system.DefDictManager;
import com.keba.lamp.system.manager.system.DefParameterManager;
import com.keba.lamp.system.service.system.DefAreaService;
import com.keba.lamp.system.service.tenant.DefTenantService;
import com.keba.lamp.system.service.tenant.DefUserService;
import com.keba.lamp.system.vo.result.system.DefDictItemResultVO;
import com.keba.lamp.tenant.entity.DefTenantAppConfig;
import com.keba.lamp.tenant.service.DefTenantAppConfigService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang3.mutable.MutableInt;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 业务实现类
 * 诉讼状案件
 * </p>
 *
 * @author twg
 * @date 2025-03-14 21:47:52
 * @create [2025-03-14 21:47:52] [twg] [代码生成器生成]
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class CaseServiceImpl extends SuperServiceImpl<CaseManager, Long, Case> implements CaseService {

    private final AppendixService appendixService;
    private final FileService fileService;
    private final PlaintffService plaintffService;
    private final DefendantService defendantService;
    private final AgentService agentService;
    private final EvidenceCaseRelService evidenceCaseRelService;
    private final EchoService echoService;
    private final ApiCallStrategy apiCallStrategy;
    private final EvidenceComponentCaseTypeRelManager evidenceComponentCaseTypeRelManager;
    private final DefDictManager defDictManager;
    private final ComFileRelManager comFileRelManager;
    private final DefParameterManager defParameterManager;
    private final CaseLogManager caseLogManager;
    private final ChannelCustomerManager channelCustomerManager;
    private final DefUserService defUserService;
    private final MsgBiz msgBiz;
    private final FileContext fileContext;
    private final DistributedLock distributedLock;
    private final AccountPrepaymentService accountPrepaymentService;
    private final DefTenantService defTenantService;
    private final PdfCommonService pdfCommonService;
    private final DefTenantAppConfigService defTenantAppConfigService;
    private final CourtAreaService courtAreaService;
    private final DefAreaService defAreaService;
    private final DocTemplateService docTemplateService;
    private final ThreadPoolExecutor executor = new ThreadPoolExecutor(3, 20, 60 * 5, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
    private final Cache<String, String> cache = CacheBuilder.newBuilder().expireAfterWrite(5, TimeUnit.MINUTES).build();
    private final String ACCOUNT_REDIS_KEY = "case:account:key:";

    @Override
    protected <SaveVO> Case saveBefore(SaveVO saveVO) {
        CaseSaveVO caseSaveVO = (CaseSaveVO) saveVO;
        caseSaveVO.setCaseState(BizConstant.CASE_STATE_DRAFT_00);
        if (Objects.isNull(caseSaveVO.getChannelCustomerId())) {
            caseSaveVO.setBusinessType(BizConstant.TENANT_BUSINESS_TYPE_01);
        } else {
            caseSaveVO.setBusinessType(BizConstant.TENANT_BUSINESS_TYPE_02);
        }
        //账户余额是否充足
        this.validAccountBalance(caseSaveVO.getBizType());
        return super.saveBefore(caseSaveVO);
    }

    @Override
    protected <SaveVO> void saveAfter(SaveVO saveVO, Case caseEntity) {
        CaseSaveVO caseSaveVO = (CaseSaveVO) saveVO;
        evidenceCaseRelService.save(caseEntity, caseSaveVO.getEvidenceVOList());
        plaintffService.save(caseSaveVO.getPlaintffSaveVOList(), caseEntity.getId());
        defendantService.save(caseSaveVO.getDefendantSaveVOList(), caseEntity.getId());
        agentService.save(caseSaveVO.getPlaintffAgentSaveVOList(), caseSaveVO.getDefendantAgentSaveVOList(), caseEntity.getId());
        saveRemarkFiles(caseEntity.getId(), caseSaveVO);
        //保存时请求扣费
        BigDecimal bizPrice = defTenantService.getPriceByCaseTypeTenantId(caseEntity.getBizType(), ContextUtil.getTenantId());
        AccountPrepayment accountPrepayment = accountPrepaymentService.getByTenantId(ContextUtil.getTenantId());
        AccountPrepaymentParamVO paramVO = new AccountPrepaymentParamVO();
        paramVO.setCaseId(caseEntity.getId());
        paramVO.setId(accountPrepayment.getId());
        paramVO.setAmount(bizPrice);
        paramVO.setCaseName(caseEntity.getCaseName());
        paramVO.setTransferTypeEnum(TransferTypeEnum.CONSUME);
        log.info("请求扣费:{}", JSON.toJSONString(paramVO));
        accountPrepaymentService.deduction(paramVO);
        log.info("扣费成功:{}", caseEntity.getCaseName());
    }

    private void saveRemarkFiles(Long caseId, CaseFileVO caseFileVO) {
        //1、案件说明文件
        List<Long> remarkFileIdList = caseFileVO.getRemarkFileIdList();
        if (CollectionUtil.isNotEmpty(remarkFileIdList)) {
            List<AppendixSaveVO> appendixSaveVOList = new ArrayList<>();
            for (int i = 0; i < remarkFileIdList.size(); i++) {
                Long remarkFileId = remarkFileIdList.get(i);
                appendixSaveVOList.add(AppendixSaveVO.build(caseId, AppendixType.Complaint.COMPLAINT__CASE__REMARK__FILE,
                        remarkFileId, i, null, null));
            }
            appendixService.save(appendixSaveVOList);
        } else {
            //未上传附件，删除附件
            appendixService.removeByBizId(Arrays.asList(caseId), AppendixType.Complaint.COMPLAINT__CASE__REMARK__FILE);
        }
    }

    @Override
    protected <UpdateVO> Case updateBefore(UpdateVO updateVO) {
        if (isH5Req()) {
            CaseUpdateVO caseUpdateVO = (CaseUpdateVO) updateVO;
            Long userId = ContextUtil.getUserId();
            String appId = StringUtils.isNotBlank(ContextUtil.getAppId()) ? ContextUtil.getAppId() : "-1";
            Map<String, String> localMap = ContextUtil.getLocalMap();
            localMap.remove(ContextConstants.TENANT_ID_HEADER);
            localMap.remove(ContextConstants.TENANT_BASE_POOL_NAME_HEADER);
            localMap.remove(ContextConstants.TENANT_EXTEND_POOL_NAME_HEADER);
            Case caseEntity = this.superManager.getByIdAndUserIdAndAppId(caseUpdateVO.getId(), userId, appId);
            if (Objects.isNull(caseEntity)) {
                throw new BizException("案件不存在");
            }
            //H5请求将当前租户ID设置为案件tenantID
            ContextUtil.setTenantId(caseEntity.getTenantId());
        }
        return super.updateBefore(updateVO);
    }

    @Override
    protected <UpdateVO> void updateAfter(UpdateVO updateVO, Case caseEntity) {
        CaseUpdateVO caseUpdateVO = (CaseUpdateVO) updateVO;
        evidenceCaseRelService.update(caseEntity, caseUpdateVO.getEvidenceVOList());
        plaintffService.update(caseUpdateVO.getPlaintffUpdateVOList(), caseEntity.getId());
        defendantService.update(caseUpdateVO.getDefendantUpdateVOList(), caseEntity.getId());
        agentService.update(caseUpdateVO.getPlaintffAgentUpdateVOList(), caseUpdateVO.getDefendantAgentUpdateVOList(), caseEntity.getId());
        saveRemarkFiles(caseEntity.getId(), caseUpdateVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delete(List<Long> ids) {
        evidenceCaseRelService.deleteByCaseIds(ids);
        plaintffService.deleteByCaseIds(ids);
        defendantService.deleteByCaseIds(ids);
        agentService.deleteByCaseIds(ids, AgentTypeEnum.PLAINTFF);
        agentService.deleteByCaseIds(ids, AgentTypeEnum.DEFENDANT);
        appendixService.removeByBizId(ids, AppendixType.Complaint.COMPLAINT__EVIDENCE__FILE);
        appendixService.removeByBizId(ids, AppendixType.Complaint.COMPLAINT__CASE__REMARK__FILE);
        return removeByIds(ids);
    }

    @Override
    public CaseResultVO getCaseById(Long id) {
        Case caseEntity = null;
        //如果是H5页面请求，且非特定租户，需要加上userId和APPID条件，并清除tenantID条件
        if (isH5Req()) {
            Long userId = ContextUtil.getUserId();
            String appId = StringUtils.isNotBlank(ContextUtil.getAppId()) ? ContextUtil.getAppId() : "-1";
            Map<String, String> localMap = ContextUtil.getLocalMap();
            localMap.remove(ContextConstants.TENANT_ID_HEADER);
            localMap.remove(ContextConstants.TENANT_BASE_POOL_NAME_HEADER);
            localMap.remove(ContextConstants.TENANT_EXTEND_POOL_NAME_HEADER);
            caseEntity = this.superManager.getByIdAndUserIdAndAppId(id, userId, appId);
        } else {
            caseEntity = getById(id);
        }
        if (caseEntity == null) {
            return null;
        }
        //将当前租户ID设置为案件tenantID
        ContextUtil.setTenantId(caseEntity.getTenantId());
        CaseResultVO resultVO = new CaseResultVO();
        BeanUtil.copyProperties(caseEntity, resultVO);
        //默认可以编辑、可以重新生成
        resultVO.setEnableUpdate(true);
        resultVO.setEnableClickGenerate(true);
        //已生成起诉状和生成中，不能编辑
        if (Objects.nonNull(caseEntity.getLastGenerateTime())
                || BizConstant.CASE_STATE_DOING_05.equals(caseEntity.getCaseState())) {
            resultVO.setEnableUpdate(false);
        }

        Map<String, String> paramMapByKey = defParameterManager.findParamMapByKey(Lists.newArrayList(BizConstant.MAX_CLICK_NUM));
        if (CollectionUtil.isNotEmpty(paramMapByKey)) {
            int maxClickNum = Integer.parseInt(paramMapByKey.get(BizConstant.MAX_CLICK_NUM));
            resultVO.setMaxClickNum(maxClickNum);
            resultVO.setEnableClickGenerate(maxClickNum > resultVO.getClickNum());
        }
        if (Objects.nonNull(resultVO.getChannelCustomerId())) {
            ChannelCustomer channelCustomer = channelCustomerManager.getById(resultVO.getChannelCustomerId());
            resultVO.setChannelCustomer(Objects.nonNull(channelCustomer) ? channelCustomer.getName() : "");
        }
        //议案专员
        if (Objects.nonNull(resultVO.getSharerUserId())) {
            DefUser defUser = defUserService.getSuperManager().getById(resultVO.getSharerUserId());
            resultVO.setSharedUserName(Objects.nonNull(defUser) ? defUser.getNickName() : "");
        }
        List<PlaintffResultVO> plaintffResultVOS = plaintffService.getResultByCaseId(id);
        List<DefendantResultVO> defendantResultVOS = defendantService.getResultByCaseId(id);
        List<AgentResultVO> plaintffAgentResultVOS = agentService.getResultByCaseId(id, AgentTypeEnum.PLAINTFF);
        List<AgentResultVO> defendantAgentResultVOS = agentService.getResultByCaseId(id, AgentTypeEnum.DEFENDANT);
        echoService.action(plaintffResultVOS);
        echoService.action(defendantResultVOS);
        echoService.action(plaintffAgentResultVOS);
        echoService.action(defendantAgentResultVOS);
        resultVO.setPlaintffResultVOList(plaintffResultVOS);
        resultVO.setDefendantResultVOList(defendantResultVOS);
        resultVO.setPlaintffAgentResultVOList(plaintffAgentResultVOS);
        resultVO.setDefendantAgentResultVOList(defendantAgentResultVOS);
        List<EvidenceResultVO> evidenceResultVOList = getEvidenceList(id, caseEntity.getBizType(), caseEntity.getCaseType());
        resultVO.setEvidenceResultVOList(evidenceResultVOList);
        //2、案件说明文件
        List<AppendixResultVO> caseRemarkFileList = appendixService.listByBizIdAndBizType(id, AppendixType.Complaint.COMPLAINT__CASE__REMARK__FILE);
        if (CollectionUtil.isNotEmpty(caseRemarkFileList)) {
            List<Long> fileIdList = caseRemarkFileList.stream().map(AppendixResultVO::getId).collect(Collectors.toList());
            List<File> files = fileService.listByIds(fileIdList);
            //Map<Long, String> accessUrlMap = fileService.findUrlById(fileIdList);
            Map<Long, File> fileMap = files.stream().collect(Collectors.toMap(File::getId, Function.identity()));
            List<CaseFileResultVO> caseRemarkFileResultVOList = caseRemarkFileList.stream().map(remarkFile -> {
                File file = fileMap.get(remarkFile.getId());
                CaseFileResultVO caseFileResultVO = new CaseFileResultVO();
                BeanUtils.copyProperties(file, caseFileResultVO);
                BeanUtils.copyProperties(remarkFile, caseFileResultVO);
                //caseFileResultVO.setUrl(accessUrlMap.get(file.getId()));
                setPicList(file, caseFileResultVO);
                return caseFileResultVO;
            }).sorted(Comparator.comparing(CaseFileResultVO::getSortValue)).collect(Collectors.toList());
            resultVO.setCaseRemarkFileResultVOList(caseRemarkFileResultVOList);
        }

        //3、返回其他材料
        CourtArea courtArea = courtAreaService.getByCourtName(caseEntity.getCourtName());
        if (Objects.nonNull(courtArea)) {
            resultVO.setAreaId(courtArea.getAreaId());
            List<DocTemplateResultVO> docTemplateResultVOList = docTemplateService.listByAreaId(courtArea.getAreaId(), id);
            docTemplateResultVOList.forEach(o -> {
                AppendixResultVO appendix = appendixService.getByBiz(o.getId(), DocTemplateTypeEnum.getByCode(o.getDocTemplateType()).getDesc());
                if (Objects.nonNull(appendix)) {
                    o.setComFileId(appendix.getId());
                }
            });
            echoService.action(docTemplateResultVOList);
            resultVO.setDocTemplateResultVOList(docTemplateResultVOList);
        }

        //4、起诉状签名文件（签名文件）
        resultVO.setSuitFileList(getCaseSignFileResult(id, AppendixType.Complaint.COMPLAINT__SUIT__FILE));
        resultVO.setEvidenceSignFileList(getCaseSignFileResult(id, AppendixType.Complaint.COMPLAINT__EVIDENCE__SIGN__FILE));
        resultVO.setIdentityMaterialFileList(getCaseSignFileResult(id, AppendixType.Complaint.COMPLAINT__IDENTITY__MATERIAL));
        //送达地址确认书模板+送达地址确认书签名版
        List<CaseFileResultVO> deliveryAddressTemplateFileResult = getCaseTemplateFileResult(id, AppendixType.Complaint.COMPLAINT__DELIVERY__ADDRESS__FILE);
        List<CaseFileResultVO> deliveryAddressSignFileResult = getCaseSignFileResult(id, AppendixType.Complaint.COMPLAINT__DELIVERY__ADDRESS__SIGN__FILE);
        resultVO.setDeliveryAddressFileList(Stream.concat(deliveryAddressTemplateFileResult.stream(), deliveryAddressSignFileResult.stream()).toList());
        //结算确认书模板+结算确认书签名版
        List<CaseFileResultVO> settleConfirmTemplateFileResult = getCaseTemplateFileResult(id, AppendixType.Complaint.COMPLAINT__SETTLE_CONFIRM__FILE);
        List<CaseFileResultVO> settleConfirmSignFileResult = getCaseSignFileResult(id, AppendixType.Complaint.COMPLAINT__SETTLE_CONFIRM__SIGN__FILE);
        resultVO.setSettleConfirmFileList(Stream.concat(settleConfirmTemplateFileResult.stream(), settleConfirmSignFileResult.stream()).toList());
        resultVO.setOtherFileList(getCaseSignFileResult(id, AppendixType.Complaint.COMPLAINT__OTHER__FILE));
        return resultVO;
    }

    /**
     * 获取签字版本案件文件资料
     * @param caseId
     * @param bizType
     * @return
     */
    private List<CaseFileResultVO> getCaseSignFileResult(Long caseId, String bizType) {
        List<AppendixResultVO> appendixResults = appendixService.listByBizIdAndBizType(caseId, bizType);
        if (CollUtil.isEmpty(appendixResults)) {
            return Lists.newArrayList();
        }
        List<Long> fileIdList = appendixResults.stream().map(AppendixResultVO::getId).collect(Collectors.toList());
        List<File> files = fileService.listByIds(fileIdList);
        Map<Long, File> fileMap = files.stream().collect(Collectors.toMap(File::getId, Function.identity()));
        List<CaseFileResultVO> caseFileResultVOList = appendixResults.stream().map(suitFile -> {
            File file = fileMap.get(suitFile.getId());
            CaseFileResultVO caseFileResultVO = new CaseFileResultVO();
            BeanUtils.copyProperties(file, caseFileResultVO);
            BeanUtils.copyProperties(suitFile, caseFileResultVO);
            return caseFileResultVO;
        }).sorted(Comparator.comparing(CaseFileResultVO::getId)).collect(Collectors.toList());
        return caseFileResultVOList;
    }

    /**
     * 获取模板文件
     * @param caseId
     * @param bizType
     * @return
     */
    private List<CaseFileResultVO> getCaseTemplateFileResult(Long caseId, String bizType) {
        List<AppendixResultVO> appendixResults = new ArrayList<>();
        DocTemplateTypeEnum docTemplateTypeEnum = DocTemplateTypeEnum.getByDesc(bizType);
        if (Objects.nonNull(docTemplateTypeEnum)) {
            appendixResults = docTemplateService.listAppendixByCaseIdAndBizType(caseId, bizType);
        }
        if (CollUtil.isEmpty(appendixResults)) {
            return Lists.newArrayList();
        }
        List<Long> fileIdList = appendixResults.stream().map(AppendixResultVO::getId).collect(Collectors.toList());
        List<File> files = fileService.listByIds(fileIdList);
        Map<Long, File> fileMap = files.stream().collect(Collectors.toMap(File::getId, Function.identity()));
        List<CaseFileResultVO> caseFileResultVOList = appendixResults.stream().map(suitFile -> {
            File file = fileMap.get(suitFile.getId());
            CaseFileResultVO caseFileResultVO = new CaseFileResultVO();
            BeanUtils.copyProperties(file, caseFileResultVO);
            BeanUtils.copyProperties(suitFile, caseFileResultVO);
            return caseFileResultVO;
        }).sorted(Comparator.comparing(CaseFileResultVO::getId)).collect(Collectors.toList());
        return caseFileResultVOList;
    }

    @Override
    public List<EvidenceResultVO> getEvidenceList(Long id, String bizType, String caseType) {
        List<EvidenceCaseRelResultVO> evidenceCaseRelResultVOList = evidenceCaseRelService.getResultByCaseId(id, bizType, caseType);
        if (CollectionUtil.isNotEmpty(evidenceCaseRelResultVOList)) {
            List<AppendixResultVO> evidenceFileList = appendixService.listByBizIdAndBizType(id, AppendixType.Complaint.COMPLAINT__EVIDENCE__FILE);
            if (CollectionUtil.isEmpty(evidenceFileList)) {
                //未上传证据图片
                List<EvidenceResultVO> evidenceResultVOList = evidenceCaseRelResultVOList.stream().map(evidenceCaseRelResultVO -> {
                    EvidenceResultVO evidenceResultVO = new EvidenceResultVO();
                    evidenceResultVO.setEvidenceCaseRelId(evidenceCaseRelResultVO.getId());
                    evidenceResultVO.setComponentName(evidenceCaseRelResultVO.getName());
                    evidenceResultVO.setSummarizeInfo(evidenceCaseRelResultVO.getSummarizeInfo());
                    evidenceResultVO.setSortValue(evidenceCaseRelResultVO.getSortValue());
                    return evidenceResultVO;
                }).sorted(Comparator.comparing(EvidenceResultVO::getSortValue)).collect(Collectors.toList());
                return evidenceResultVOList;
            }

            List<Long> fileIdList = evidenceFileList.stream().map(AppendixResultVO::getId).collect(Collectors.toList());
            Map<String, List<AppendixResultVO>> evidenceGroupMap = evidenceFileList.stream().collect(Collectors.groupingBy(AppendixResultVO::getExtendColumn));
            List<File> files = fileService.listByIds(fileIdList);
            //Map<Long, String> accessUrlMap = fileService.findUrlById(fileIdList);
            Map<Long, File> fileMap = files.stream().collect(Collectors.toMap(File::getId, Function.identity()));
            List<EvidenceResultVO> evidenceResultVOList = evidenceCaseRelResultVOList.stream().map(evidenceCaseRelResultVO -> {
                EvidenceResultVO evidenceResultVO = new EvidenceResultVO();
                evidenceResultVO.setEvidenceCaseRelId(evidenceCaseRelResultVO.getId());
                evidenceResultVO.setComponentName(evidenceCaseRelResultVO.getName());
                evidenceResultVO.setSummarizeInfo(evidenceCaseRelResultVO.getSummarizeInfo());
                evidenceResultVO.setSortValue(evidenceCaseRelResultVO.getSortValue());
                evidenceResultVO.setTotalPicNum(0);
                List<AppendixResultVO> appendixResultVOS = evidenceGroupMap.getOrDefault(String.valueOf(evidenceCaseRelResultVO.getId()), new ArrayList<>());
                if (CollectionUtil.isNotEmpty(appendixResultVOS)) {
                    List<CaseFileResultVO> caseFileResultVOList = appendixResultVOS.stream().map(appendixResultVO -> {
                        File file = fileMap.get(appendixResultVO.getId());
                        CaseFileResultVO caseFileResultVO = new CaseFileResultVO();
                        BeanUtils.copyProperties(file, caseFileResultVO);
                        BeanUtils.copyProperties(appendixResultVO, caseFileResultVO);
                        //caseFileResultVO.setUrl(accessUrlMap.get(file.getId()));
                        setPicList(file, caseFileResultVO);
                        return caseFileResultVO;
                    }).sorted(Comparator.comparing(CaseFileResultVO::getSortValue)).collect(Collectors.toList());
                    evidenceResultVO.setCaseFileResultVOList(caseFileResultVOList);
                    int totalPicNum = 0;
                    if (CollectionUtil.isNotEmpty(caseFileResultVOList)) {
                        totalPicNum = caseFileResultVOList.stream().mapToInt(CaseFileResultVO::getPicNum).sum();
                    }
                    evidenceResultVO.setTotalPicNum(totalPicNum);
                }
                return evidenceResultVO;
            }).sorted(Comparator.comparing(EvidenceResultVO::getSortValue)).collect(Collectors.toList());
            int startPage = 1;
            for (int i = 0; i < evidenceResultVOList.size(); i++) {
                EvidenceResultVO evidenceGroup = evidenceResultVOList.get(i);
                if (CollectionUtils.isNotEmpty(evidenceGroup.getCaseFileResultVOList())) {
                    int totalPicNum = evidenceGroup.getTotalPicNum();
                    int endPage = startPage + totalPicNum - 1;
                    evidenceGroup.setStartPage(startPage);
                    evidenceGroup.setEndPage(endPage);
                    startPage += totalPicNum;
                }
            }
            return evidenceResultVOList;
        }
        return Collections.emptyList();
    }

    private void setPicList(File file, CaseFileResultVO caseFileResultVO) {
        if (BizConstant.SUFFIX_PDF.equalsIgnoreCase(file.getSuffix())) {
            ComFileRel comFileRel = comFileRelManager.getByFileId(file.getId());
            caseFileResultVO.setPicNum(Objects.nonNull(comFileRel) ? comFileRel.getPicNum() : 0);
        } else if (FileType.IMAGE.eq(file.getFileType())) {
            caseFileResultVO.setPicNum(1);
        }
    }

    private String setPicCutSize(String url) {
        try {
            String picCutSize = cache.get(BizConstant.PIC_CUT_SIZE, () -> {
                Map<String, String> paramMapByKey = defParameterManager.findParamMapByKey(Lists.newArrayList(BizConstant.PIC_CUT_SIZE));
                if (CollectionUtil.isNotEmpty(paramMapByKey)) {
                    return paramMapByKey.get(BizConstant.PIC_CUT_SIZE);
                }
                return "";
            });
            if (StringUtils.isNotBlank(picCutSize)) {
                int expiresIndex = url.indexOf("?Expires");
                if (expiresIndex >= 0) {
                    url = url.substring(0, expiresIndex);
                }
                return url + picCutSize;
            }
        } catch (Exception e) {
            log.error("图片添加剪切参数异常：", e);
        }
        return url;
    }

    private List<String> setPicCutSize(List<String> urlList) {
        if (CollectionUtil.isNotEmpty(urlList)) {
            return urlList.stream().map(url -> setPicCutSize(url)).collect(Collectors.toList());
        }
        return Lists.newArrayList();
    }

    @Transactional
    @Override
    public boolean callAi(Long caseId) {
        CaseResultVO caseResultVO = this.getCaseById(caseId);
        List<EvidenceResultVO> evidenceResultVOList = caseResultVO.getEvidenceResultVOList();
        List<PlaintffResultVO> plaintffResultVOList = caseResultVO.getPlaintffResultVOList();
        List<DefendantResultVO> defendantResultVOList = caseResultVO.getDefendantResultVOList();
        //2、修改案件状态
        this.updateCaseStatus(caseId, BizConstant.CASE_STATE_DOING_05);
        //3、异步请求大模型
        asyncProcessAiResult(ContextUtil.getTenantId(), ContextUtil.getUserId(), caseResultVO);
        return true;
    }

    /**
     * 生成大模型入参
     * @param caseResultVO
     * @return
     */
    private AiCallModelRequestQuery getAiCallModelRequestQuery(CaseResultVO caseResultVO) {
        try {
            List<PlaintffResultVO> plaintffResultVOList = caseResultVO.getPlaintffResultVOList();
            List<DefendantResultVO> defendantResultVOList = caseResultVO.getDefendantResultVOList();
            List<AgentResultVO> plaintffAgentResultVOList = caseResultVO.getPlaintffAgentResultVOList();
            List<AgentResultVO> defendantAgentResultVOList = caseResultVO.getDefendantAgentResultVOList();
            List<EvidenceResultVO> evidenceResultVOList = caseResultVO.getEvidenceResultVOList();
            List<CaseFileResultVO> caseRemarkFileResultVOList = caseResultVO.getCaseRemarkFileResultVOList();
            List<AiCallModelRequestQuery.CompletionContent> completionContents = new ArrayList<>();

            for (int i = 0; i < plaintffResultVOList.size(); i++) {
                PlaintffResultVO plaintffResultVO = plaintffResultVOList.get(i);
                List<String> longPicUrlList = getLongPicUrlList("原告" + (i + 1), plaintffResultVO.getFileList());
                plaintffResultVO.setLongPicUrlList(longPicUrlList);
            }
            if (CollectionUtil.isNotEmpty(plaintffAgentResultVOList)) {
                for (int i = 0; i < plaintffAgentResultVOList.size(); i++) {
                    AgentResultVO agentResultVO = plaintffAgentResultVOList.get(i);
                    List<String> longPicUrlList = getLongPicUrlList("原告代理人" + (i + 1), agentResultVO.getFileList());
                    agentResultVO.setLongPicUrlList(longPicUrlList);
                }
            }
            for (int i = 0; i < defendantResultVOList.size(); i++) {
                DefendantResultVO defendantResultVO = defendantResultVOList.get(i);
                List<String> longPicUrlList = getLongPicUrlList("被告" + (i + 1), defendantResultVO.getFileList());
                defendantResultVO.setLongPicUrlList(longPicUrlList);
            }
            if (CollectionUtil.isNotEmpty(defendantAgentResultVOList)) {
                for (int i = 0; i < defendantAgentResultVOList.size(); i++) {
                    AgentResultVO agentResultVO = defendantAgentResultVOList.get(i);
                    List<String> longPicUrlList = getLongPicUrlList("被告代理人" + (i + 1), agentResultVO.getFileList());
                    agentResultVO.setLongPicUrlList(longPicUrlList);
                }
            }

            for (EvidenceResultVO evidenceResultVO : evidenceResultVOList) {
                List<String> longPicUrlList = getLongPicUrlList(evidenceResultVO.getComponentName(), evidenceResultVO.getCaseFileResultVOList());
                evidenceResultVO.setLongPicUrlList(longPicUrlList);
            }
            List<String> remarkPicUrlList = getLongPicUrlList("案件说明", caseRemarkFileResultVOList);
            List<String> audioUrlList = CollectionUtils.isEmpty(caseRemarkFileResultVOList)
                    ? Lists.newArrayList()
                    : caseRemarkFileResultVOList.stream().filter(caseFileResultVO ->
                    FileType.AUDIO.eq(caseFileResultVO.getFileType())).map(CaseFileResultVO::getUrl).collect(Collectors.toList());
            Map<String, Object> extra = new HashMap<>();
            MutableInt index = new MutableInt(1);
            Map<String, List<DefDictItemResultVO>> dictMapItemList = defDictManager.findDictMapItemListByKey(Lists.newArrayList(BizConstant.LLM_VARIABLE));
            Map<String, DefDictItemResultVO> varDictMap = new HashMap<>();
            if (CollectionUtil.isNotEmpty(dictMapItemList)) {
                varDictMap = dictMapItemList.get(BizConstant.LLM_VARIABLE).stream().collect(Collectors.toMap(DefDictItemResultVO::getKey, Function.identity()));
            }
            if (CollectionUtil.isNotEmpty(plaintffResultVOList)) {
                DefDictItemResultVO plaintffText = varDictMap.get(ComplaintCaseConstant.PLAINTFF_TEXT_KEY);
                List<String> plaintffGroupNames = new ArrayList<>();
                for (int i = 0; i < plaintffResultVOList.size(); i++) {
                    int begin = index.getValue();
                    PlaintffResultVO plaintffResultVO = plaintffResultVOList.get(i);
                    List<String> longPicUrlList = plaintffResultVO.getLongPicUrlList();
                    index.add(longPicUrlList.size());
                    longPicUrlList.stream().forEach(picUrl ->
                            completionContents.add(AiCallModelRequestQuery.CompletionContent.builder().type(AiFileType.IMAGE.getAiType()).fileUrl(picUrl).build())
                    );
                    String text = "原告序号:" + i + ",照片：第" + begin + "张到第" + (index.getValue() - 1) + "张,联系电话：" + plaintffResultVO.getMobile();
                    plaintffGroupNames.add(text);
                }
                extra.put(plaintffText.getName(), CollectionUtil.join(plaintffGroupNames, ";"));
            }

            DefDictItemResultVO plaintffAgentText = varDictMap.get(ComplaintCaseConstant.PLAINTFF_AGENT_TEXT_KEY);
            if (CollectionUtil.isNotEmpty(plaintffAgentResultVOList)) {
                List<String> agentGroupNames = new ArrayList<>();
                for (int i = 0; i < plaintffAgentResultVOList.size(); i++) {
                    int begin = index.getValue();
                    AgentResultVO agentResultVO = plaintffAgentResultVOList.get(i);
                    List<String> longPicUrlList = agentResultVO.getLongPicUrlList();
                    index.add(longPicUrlList.size());
                    longPicUrlList.stream().forEach(picUrl ->
                            completionContents.add(AiCallModelRequestQuery.CompletionContent.builder().type(AiFileType.IMAGE.getAiType()).fileUrl(picUrl).build())
                    );
                    String text = "原告代理人序号:" + i + ",照片：第" + begin + "张到第" + (index.getValue() - 1) + "张,联系电话：" + agentResultVO.getMobile();
                    agentGroupNames.add(text);
                }
                extra.put(plaintffAgentText.getName(), CollectionUtil.join(agentGroupNames, ";"));
            } else {
                extra.put(plaintffAgentText.getName(), "无");
            }

            if (CollectionUtil.isNotEmpty(defendantResultVOList)) {
                DefDictItemResultVO defendantText = varDictMap.get(ComplaintCaseConstant.DEFENDANT_TEXT_KEY);

                List<String> defendantGroupNames = new ArrayList<>();
                for (int i = 0; i < defendantResultVOList.size(); i++) {
                    int begin = index.getValue();
                    DefendantResultVO defendantResultVO = defendantResultVOList.get(i);
                    List<String> longPicUrlList = defendantResultVO.getLongPicUrlList();
                    index.add(longPicUrlList.size());
                    longPicUrlList.stream().forEach(picUrl ->
                            completionContents.add(AiCallModelRequestQuery.CompletionContent.builder().type(AiFileType.IMAGE.getAiType()).fileUrl(picUrl).build())
                    );
                    String text = "被告序号:" + i + ",照片：第" + begin + "张到第" + (index.getValue() - 1) + "张,联系电话：" + defendantResultVO.getMobile();
                    defendantGroupNames.add(text);
                }
                extra.put(defendantText.getName(), CollectionUtil.join(defendantGroupNames, ";"));
            }

            DefDictItemResultVO defendantAgentText = varDictMap.get(ComplaintCaseConstant.DEFENDANT_AGENT_TEXT_KEY);
            if (CollectionUtil.isNotEmpty(defendantAgentResultVOList)) {
                List<String> agentGroupNames = new ArrayList<>();
                for (int i = 0; i < defendantAgentResultVOList.size(); i++) {
                    int begin = index.getValue();
                    AgentResultVO agentResultVO = defendantAgentResultVOList.get(i);
                    List<String> longPicUrlList = agentResultVO.getLongPicUrlList();
                    index.add(longPicUrlList.size());
                    longPicUrlList.stream().forEach(picUrl ->
                            completionContents.add(AiCallModelRequestQuery.CompletionContent.builder().type(AiFileType.IMAGE.getAiType()).fileUrl(picUrl).build())
                    );
                    String text = "被告代理人序号:" + i + ",照片：第" + begin + "张到第" + (index.getValue() - 1) + "张,联系电话：" + agentResultVO.getMobile();
                    agentGroupNames.add(text);
                }
                extra.put(defendantAgentText.getName(), CollectionUtil.join(agentGroupNames, ";"));
            } else {
                extra.put(defendantAgentText.getName(), "无");
            }

            if (CollectionUtil.isNotEmpty(evidenceResultVOList)) {
                DefDictItemResultVO evidenceGroup = varDictMap.get(ComplaintCaseConstant.EVIDENCE_GROUP_NAME_AND_IMAGE);
                List<String> evidenceGroupNames = new ArrayList<>();
                for (int i = 0; i < evidenceResultVOList.size(); i++) {
                    EvidenceResultVO evidenceResultVO = evidenceResultVOList.get(i);
                    int evidenceGroupBegin = index.getValue();
                    List<String> longPicUrlList = evidenceResultVO.getLongPicUrlList();
                    index.add(longPicUrlList.size());
                    longPicUrlList.stream().forEach(picUrl ->
                            completionContents.add(AiCallModelRequestQuery.CompletionContent.builder().type(AiFileType.IMAGE.getAiType()).fileUrl(picUrl).build())
                    );
                    String evidenceFormat = "%s,证据照片：第%d张到第%d张";
                    String text = evidenceFormat.formatted(evidenceResultVO.getComponentName(), evidenceGroupBegin, index.getValue() - 1);
                    evidenceGroupNames.add(text);
                }
                extra.put(evidenceGroup.getName(), CollectionUtil.join(evidenceGroupNames, ";"));
            }
            DefDictItemResultVO remarkTextDict = varDictMap.get(ComplaintCaseConstant.REMARK_TEXT);
            if (Objects.nonNull(remarkTextDict)) {
                extra.put(remarkTextDict.getName(), StringUtils.isNotBlank(caseResultVO.getRemark()) ? caseResultVO.getRemark() : "无");
            }

            DefDictItemResultVO remarkFileTextDict = varDictMap.get(ComplaintCaseConstant.REMARK_FILE_TEXT_KEY);
            if (CollectionUtil.isNotEmpty(remarkPicUrlList) || CollectionUtil.isNotEmpty(audioUrlList)) {
                int begin = index.getValue();
                index.add(remarkPicUrlList.size() + audioUrlList.size());
                remarkPicUrlList.forEach(picUrl -> {
                    completionContents.add(AiCallModelRequestQuery.CompletionContent.builder().type(AiFileType.IMAGE.getAiType()).fileUrl(picUrl).build());
                });
                audioUrlList.forEach(audioUrl -> {
                    completionContents.add(AiCallModelRequestQuery.CompletionContent.builder().type(AiFileType.AUDIO.getAiType()).fileUrl(audioUrl).build());
                });
                int end = index.getValue() - 1;
                extra.put(remarkFileTextDict.getName(), "第" + begin + "条到第" + end + "条");
            } else {
                extra.put(remarkFileTextDict.getName(), "无");
            }

            Map<String, List<DefDictItemResultVO>> aiConfigDictMap = defDictManager.findDictMapItemListByKey(Lists.newArrayList(BizConstant.AI_CONFIG));
            ArgumentAssert.notEmpty(aiConfigDictMap, "AI字典参数未配置");
            List<DefDictItemResultVO> dictList = aiConfigDictMap.get(BizConstant.AI_CONFIG);
            DefDictItemResultVO appIdConfig = dictList.stream().filter(dict -> BizConstant.AI_APPID.equals(dict.getKey())).findFirst().orElse(null);
            DefDictItemResultVO appKeyConfig = dictList.stream().filter(dict -> BizConstant.AI_APPKEY.equals(dict.getKey())).findFirst().orElse(null);
            ArgumentAssert.notNull(appIdConfig, "AI appid参数未配置");
            ArgumentAssert.notNull(appKeyConfig, "AI appkey参数未配置");
            AiCallModelRequestQuery query = AiCallModelRequestQuery.builder()
                    .bizId(UUID.randomUUID().toString())
                    .appId(Long.parseLong(appIdConfig.getName()))
                    .appKey(appKeyConfig.getName())
                    .completionContents(completionContents)
                    .extra(extra)
                    .build();
            return query;
        } catch (Exception e) {
            log.error("组装AI请求参数失败", e);
            throw new BizException("组装AI请求参数失败");
        }
    }

    /**
     * 合并长图
     *
     * @param caseFileResultVOList
     * @return
     * @throws IOException
     */
    private List<String> getLongPicUrlList(String picName, List<CaseFileResultVO> caseFileResultVOList) throws IOException {
        if (CollectionUtils.isEmpty(caseFileResultVOList)) {
            return Lists.newArrayList();
        }
        String bizType = caseFileResultVOList.get(0).getBizType();
        FileStorageType storageType = caseFileResultVOList.get(0).getStorageType();
        String bucket = caseFileResultVOList.get(0).getBucket();
        FileUploadVO fileUploadVO = new FileUploadVO();
        fileUploadVO.setBucket(bucket);
        fileUploadVO.setBizType(bizType);
        fileUploadVO.setStorageType(storageType);
//        List<CaseFileResultVO> imageFileList = caseFileResultVOList.stream().filter(caseFileResultVO ->
//                FileType.IMAGE.eq(caseFileResultVO.getFileType())).collect(Collectors.toList());
//        List<CaseFileResultVO> pdfFileList = caseFileResultVOList.stream().filter(caseFileResultVO ->
//                "pdf".equalsIgnoreCase(caseFileResultVO.getSuffix())).collect(Collectors.toList());
        List<String> subImageUrls = new ArrayList<>();
        List<String> longImageUrls = new ArrayList<>();
        caseFileResultVOList.forEach(caseFileResultVO -> {
            if (FileType.IMAGE.eq(caseFileResultVO.getFileType())) {
                subImageUrls.add(caseFileResultVO.getUrl());
            } else if ("pdf".equalsIgnoreCase(caseFileResultVO.getSuffix())) {
                //拆分PDF文档为图片存储
                String originalFileName = caseFileResultVO.getOriginalFileName();
                try {
                    HttpResponse httpResponse = HttpRequest.get(caseFileResultVO.getUrl()).execute();
                    if (httpResponse.isOk()) {
                        InputStream pdfInputStream = httpResponse.bodyStream();
                        PDDocument document = PDDocument.load(pdfInputStream);
                        //移除加密
                        document.setAllSecurityToBeRemoved(true);
                        PDFRenderer renderer = new PDFRenderer(document);

                        for (int i = 0; i < document.getNumberOfPages(); i++) {
                            BufferedImage image = renderer.renderImageWithDPI(i, 150); // 设置图片分辨率为150 DPI
                            String fileName = originalFileName.replace(".pdf", "_" + i + ".png");
                            InputStream inputStream = bufferedImageToInputStream(image, "png");
                            File imageFile = fileContext.upload(inputStream, fileName, fileUploadVO);
                            subImageUrls.add(imageFile.getUrl());
                        }
                        document.close();
                    }
                } catch (IOException e) {
                    log.error("拆分PDF文档为图片存储失败", e);
                    throw new BizException("拆分PDF文档为图片存储失败");
                }
            }
        });

        if (CollectionUtils.isNotEmpty(subImageUrls)) {
            log.info("单张图片列表:{}", subImageUrls);

            int pageCount = subImageUrls.size();
            int picNum = pageCount / 20;
            if (pageCount % 20 != 0) {
                picNum += 1;
            }
            log.info("生成图片名称:{}, 共{}张，拆分成{}张图片", picName, pageCount, picNum);
            for (int i = 0; i < picNum; i++) {
                int start = i * 20;
                int end = (i + 1) * 20 < pageCount ? (i + 1) * 20 : pageCount;
                log.info("第{}张长图,合并第{}-{}张", i + 1, start + 1, end);
                List<String> imageUrlList = subImageUrls.subList(start, end);
                //裁剪图片后，拼接成一张大图
                BufferedImage longImage = ImageUtil.mergeImages(setPicCutSize(imageUrlList));
                InputStream imageInputStream = bufferedImageToInputStream(longImage, "png");
                File imageFile = fileContext.upload(imageInputStream, picName + "_" + i + ".png", fileUploadVO);
                longImageUrls.add(imageFile.getUrl());
            }
        }
        log.info("长图列表:{}", longImageUrls);
        return longImageUrls;
    }

    public static InputStream bufferedImageToInputStream(BufferedImage image, String formatName) throws IOException {
        // 创建输出流
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        // 将BufferedImage写入ByteArrayOutputStream中
        ImageIO.write(image, formatName, byteArrayOutputStream);
        // 将ByteArrayOutputStream的内容转化为输入流
        return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
    }

    /**
     * 校验录入是否完整
     *
     * @param caseSaveVO
     */
    private static void validSaveVO(CaseSaveVO caseSaveVO) {
        List<EvidenceVO> evidenceVOList = caseSaveVO.getEvidenceVOList();
        List<PlaintffSaveVO> plaintffVOList = caseSaveVO.getPlaintffSaveVOList();
        List<DefendantSaveVO> defendantVOList = caseSaveVO.getDefendantSaveVOList();
        if (CollectionUtil.isEmpty(evidenceVOList)
                || CollectionUtil.isEmpty(plaintffVOList)
                || CollectionUtil.isEmpty(defendantVOList)) {
            throw new BizException("案件材料不完整，请录入完整后再提交");
        }
        boolean plaintffPhoneEmpty = plaintffVOList.stream().anyMatch(plaintff -> StringUtils.isBlank(plaintff.getMobile()));
        if (plaintffPhoneEmpty) {
            throw new BizException("原告手机号未录入");
        }
        boolean defendantPhoneEmpty = defendantVOList.stream().anyMatch(defendant -> StringUtils.isBlank(defendant.getMobile()));
        if (defendantPhoneEmpty) {
            throw new BizException("被告手机号未录入");
        }
        boolean componentNameEmpty = evidenceVOList.stream().anyMatch(evidence -> StringUtils.isBlank(evidence.getComponentName()));
        if (componentNameEmpty) {
            throw new BizException("证据组名称未录入");
        }
        boolean componentNameRepeat = evidenceVOList.stream().map(EvidenceVO::getComponentName).distinct().count() < evidenceVOList.size();
        if (componentNameRepeat) {
            throw new BizException("证据组名称不能重复");
        }
        EvidenceVO componentEmptyGroup = evidenceVOList.stream().filter(evidence -> CollectionUtil.isEmpty(evidence.getFileIdList())).findFirst().orElse(null);
        if (Objects.nonNull(componentEmptyGroup)) {
            throw new BizException("证据组[" + componentEmptyGroup.getComponentName() + "]文件未上传");
        }
    }

    private static void validUpdateVO(CaseUpdateVO caseUpdateVO) {
        List<EvidenceVO> evidenceVOList = caseUpdateVO.getEvidenceVOList();
        List<PlaintffUpdateVO> plaintffVOList = caseUpdateVO.getPlaintffUpdateVOList();
        List<DefendantUpdateVO> defendantVOList = caseUpdateVO.getDefendantUpdateVOList();
        if (CollectionUtil.isEmpty(evidenceVOList)
                || CollectionUtil.isEmpty(plaintffVOList)
                || CollectionUtil.isEmpty(defendantVOList)) {
            throw new BizException("案件材料不完整，请录入完整后再提交");
        }
        boolean plaintffPhoneEmpty = plaintffVOList.stream().anyMatch(plaintff -> StringUtils.isBlank(plaintff.getMobile()));
        if (plaintffPhoneEmpty) {
            throw new BizException("原告手机号未录入");
        }
        boolean defendantPhoneEmpty = defendantVOList.stream().anyMatch(defendant -> StringUtils.isBlank(defendant.getMobile()));
        if (defendantPhoneEmpty) {
            throw new BizException("被告手机号未录入");
        }
        boolean componentNameEmpty = evidenceVOList.stream().anyMatch(evidence -> StringUtils.isBlank(evidence.getComponentName()));
        if (componentNameEmpty) {
            throw new BizException("证据组名称未录入");
        }
        boolean componentNameRepeat = evidenceVOList.stream().map(EvidenceVO::getComponentName).distinct().count() < evidenceVOList.size();
        if (componentNameRepeat) {
            throw new BizException("证据组名称不能重复");
        }
        EvidenceVO componentEmptyGroup = evidenceVOList.stream().filter(evidence -> CollectionUtil.isEmpty(evidence.getFileIdList())).findFirst().orElse(null);
        if (Objects.nonNull(componentEmptyGroup)) {
            throw new BizException("证据组[" + componentEmptyGroup.getComponentName() + "]文件未上传");
        }
    }

    private static void validCaseVO(CaseResultVO caseResultVO) {
        List<EvidenceResultVO> evidenceVOList = caseResultVO.getEvidenceResultVOList();
        List<PlaintffResultVO> plaintffVOList = caseResultVO.getPlaintffResultVOList();
        List<DefendantResultVO> defendantVOList = caseResultVO.getDefendantResultVOList();
        if (CollectionUtil.isEmpty(evidenceVOList)
                || CollectionUtil.isEmpty(plaintffVOList)
                || CollectionUtil.isEmpty(defendantVOList)) {
            throw new BizException("案件材料不完整，请录入完整后再提交");
        }
        boolean plaintffPhoneEmpty = plaintffVOList.stream().anyMatch(plaintff -> StringUtils.isBlank(plaintff.getMobile()));
        if (plaintffPhoneEmpty) {
            throw new BizException("原告手机号未录入");
        }
        boolean defendantPhoneEmpty = defendantVOList.stream().anyMatch(defendant -> StringUtils.isBlank(defendant.getMobile()));
        if (defendantPhoneEmpty) {
            throw new BizException("被告手机号未录入");
        }
        boolean componentNameEmpty = evidenceVOList.stream().anyMatch(evidence -> StringUtils.isBlank(evidence.getComponentName()));
        if (componentNameEmpty) {
            throw new BizException("证据组名称未录入");
        }
        boolean componentNameRepeat = evidenceVOList.stream().map(EvidenceResultVO::getComponentName).distinct().count() < evidenceVOList.size();
        if (componentNameRepeat) {
            throw new BizException("证据组名称不能重复");
        }
        EvidenceResultVO componentEmptyGroup = evidenceVOList.stream().filter(evidence ->
                CollectionUtil.isEmpty(evidence.getCaseFileResultVOList())).findFirst().orElse(null);
        if (Objects.nonNull(componentEmptyGroup)) {
            throw new BizException("证据组[" + componentEmptyGroup.getComponentName() + "]文件未上传");
        }
    }

    /**
     * 校验案件生成次数
     *
     * @param caseId
     */
    private void validClickNum(Long caseId) {
        Case caseEntity = this.superManager.getById(caseId);
        Map<String, String> paramMapByKey = defParameterManager.findParamMapByKey(Lists.newArrayList(BizConstant.MAX_CLICK_NUM));
        if (Objects.nonNull(caseEntity) && CollectionUtil.isNotEmpty(paramMapByKey)) {
            int maxClickNum = Integer.parseInt(paramMapByKey.get(BizConstant.MAX_CLICK_NUM));
            if (maxClickNum <= caseEntity.getClickNum()) {
                throw new BizException("该案件已超出最大可生成次数");
            }
        }
    }


    /**
     * 线程池处理ai请求
     *
     * @param tenantId
     * @param caseResultVO
     */
    private void asyncProcessAiResult(Long tenantId, Long userId, CaseResultVO caseResultVO) {
        executor.submit(() -> {
            String redisKey = ACCOUNT_REDIS_KEY + tenantId;
            boolean isSuccess = false;
            try {
                ContextUtil.setTenantId(tenantId);
                ContextUtil.setUserId(userId);
                List<PlaintffResultVO> plaintffResultVOList = caseResultVO.getPlaintffResultVOList();
                List<DefendantResultVO> defendantResultVOList = caseResultVO.getDefendantResultVOList();
                List<AgentResultVO> plaintffAgentResultVOList = caseResultVO.getPlaintffAgentResultVOList();
                List<AgentResultVO> defendantAgentResultVOList = caseResultVO.getDefendantAgentResultVOList();
                List<EvidenceResultVO> evidenceResultVOList = caseResultVO.getEvidenceResultVOList();
                List<CaseFileResultVO> remarkFileResultVOList = caseResultVO.getCaseRemarkFileResultVOList();
                AiCallModelRequestQuery query = getAiCallModelRequestQuery(caseResultVO);

                log.info("请求科巴ai:{}", JSON.toJSONString(query));
                Object result = apiCallStrategy.call(query);
                log.info("请求科巴ai结果:{}", JSON.toJSONString(result));
                String aiResult = result.toString();

                //解析ai
                String plaintffCity = "";
                String plaintffProvince = "";
                List<String> plaintffList = new ArrayList<>();
                Matcher plaintffMatcher = ComplaintCaseConstant.PLAINTFF_PATTERN.matcher(aiResult);
                while (plaintffMatcher.find()) {
                    String match = plaintffMatcher.group(1);
                    log.info("原告信息:{}", match);
                    List<AiPlaintffResultVO> list = JSON.parseArray(match, AiPlaintffResultVO.class);
                    for (AiPlaintffResultVO aiPlaintffResultVO : list) {
                        Integer i = aiPlaintffResultVO.getIndex();
                        String plaintffName = aiPlaintffResultVO.getName();
                        String plaintffInfo = aiPlaintffResultVO.getInfo();
                        String type = aiPlaintffResultVO.getType();
                        AiPlaintffResultVO.PlaintffDetail plaintffDetail = aiPlaintffResultVO.getPlaintffDetail();
                        plaintffCity = StringUtils.isBlank(plaintffCity) ? plaintffDetail.getCity() : plaintffCity;
                        plaintffProvince = StringUtils.isBlank(plaintffProvince) ? plaintffDetail.getProvince() : plaintffProvince;
                        //解析原告信息
                        if (CollectionUtils.size(plaintffResultVOList) > i
                                && Objects.nonNull(i) && StringUtils.isNotBlank(plaintffName)) {
                            plaintffList.add(plaintffName);
                            PlaintffResultVO plaintffResultVO = plaintffResultVOList.get(i);
                            Plaintff plaintff = new Plaintff();
                            plaintff.setId(plaintffResultVO.getId());
                            plaintff.setName(plaintffName);
                            plaintff.setSummarizeInfo(plaintffInfo);
                            if ("自然人".equals(type)) {
                                plaintff.setType(0);
                                plaintff.setIdCard(plaintffDetail.getIdCardNo());
                                if (StringUtils.isNotBlank(plaintffDetail.getBirthday())) {
                                    plaintff.setBirthDate(DateUtil.parse(plaintffDetail.getBirthday(), DatePattern.PURE_DATE_FORMAT).toLocalDateTime().toLocalDate());
                                }
                                String sex = null;
                                if ("男".equals(plaintffDetail.getSex())) {
                                    sex = "1";
                                } else if ("女".equals(plaintffDetail.getSex())) {
                                    sex = "2";
                                }
                                plaintff.setSex(sex);
                                plaintff.setAddress(plaintffDetail.getAddress());
                            } else if ("法人".equals(type)) {
                                plaintff.setType(1);
                                plaintff.setIdCard(plaintffDetail.getCreditCode());
                                plaintff.setAddress(plaintffDetail.getCompanyAddress());
                                plaintff.setLegalPersonName(plaintffDetail.getLegalPerson());
                            }

                            plaintffService.getSuperManager().updateById(plaintff);
                        }
                    }
                }

                Matcher plaintffAgentMatcher = ComplaintCaseConstant.PLAINTFF_AGENT_PATTERN.matcher(aiResult);
                while (plaintffAgentMatcher.find()) {
                    String match = plaintffAgentMatcher.group(1);
                    log.info("原告代理人信息:{}", match);
                    if (StringUtils.isBlank(match)) {
                        break;
                    }
                    List<AiPlaintffAgentResultVO> list = JSON.parseArray(match, AiPlaintffAgentResultVO.class);
                    for (AiPlaintffAgentResultVO aiPlaintffAgentResultVO : list) {
                        Integer i = aiPlaintffAgentResultVO.getIndex();
                        String plaintffAgentName = aiPlaintffAgentResultVO.getName();
                        String plaintffAgentInfo = aiPlaintffAgentResultVO.getInfo();
                        AiPlaintffAgentResultVO.PlaintffDetail plaintffDetail = aiPlaintffAgentResultVO.getPlaintffDetail();

                        //解析原告代理人信息
                        if (CollectionUtils.size(plaintffAgentResultVOList) > i
                                && Objects.nonNull(i) && StringUtils.isNotBlank(plaintffAgentName)) {
                            AgentResultVO agentResultVO = plaintffAgentResultVOList.get(i);
                            Agent plaintffAgent = new Agent();
                            plaintffAgent.setId(agentResultVO.getId());
                            plaintffAgent.setName(plaintffAgentName);
                            plaintffAgent.setSummarizeInfo(plaintffAgentInfo);
                            plaintffAgent.setType(0);
                            plaintffAgent.setIdCard(plaintffDetail.getIdCardNo());
                            if (StringUtils.isNotBlank(plaintffDetail.getBirthday())) {
                                plaintffAgent.setBirthDate(DateUtil.parse(plaintffDetail.getBirthday(), DatePattern.PURE_DATE_FORMAT).toLocalDateTime().toLocalDate());
                            }
                            String sex = null;
                            if ("男".equals(plaintffDetail.getSex())) {
                                sex = "1";
                            } else if ("女".equals(plaintffDetail.getSex())) {
                                sex = "2";
                            }
                            plaintffAgent.setSex(sex);
                            plaintffAgent.setAddress(plaintffDetail.getAddress());
                            agentService.getSuperManager().updateById(plaintffAgent);
                        }
                    }
                }

                List<String> defendantList = new ArrayList<>();
                Matcher defendantMatcher = ComplaintCaseConstant.DEFENDANT_PATTERN.matcher(aiResult);
                while (defendantMatcher.find()) {
                    String match = defendantMatcher.group(1);
                    log.info("被告信息:{}", match);
                    List<AiDefendantResultVO> list = JSON.parseArray(match, AiDefendantResultVO.class);
                    for (AiDefendantResultVO aiDefendantResultVO : list) {
                        Integer i = aiDefendantResultVO.getIndex();
                        String defendantName = aiDefendantResultVO.getName();
                        String defendantInfo = aiDefendantResultVO.getInfo();
                        String type = aiDefendantResultVO.getType();
                        AiDefendantResultVO.DefendantDetail defendantDetail = aiDefendantResultVO.getDefendantDetail();
                        //解析被告信息
                        if (CollectionUtils.size(defendantResultVOList) > i
                                && Objects.nonNull(i) && StringUtils.isNotBlank(defendantName)) {
                            defendantList.add(defendantName);
                            DefendantResultVO defendantResultVO = defendantResultVOList.get(i);
                            Defendant defendant = new Defendant();
                            defendant.setId(defendantResultVO.getId());
                            defendant.setName(defendantName);
                            defendant.setSummarizeInfo(defendantInfo);
                            if ("自然人".equals(type)) {
                                defendant.setType(0);
                                defendant.setIdCard(defendantDetail.getIdCardNo());
                                if (StringUtils.isNotBlank(defendantDetail.getBirthday())) {
                                    defendant.setBirthDate(DateUtil.parse(defendantDetail.getBirthday(), DatePattern.PURE_DATE_FORMAT).toLocalDateTime().toLocalDate());
                                }
                                String sex = null;
                                if ("男".equals(defendantDetail.getSex())) {
                                    sex = "1";
                                } else if ("女".equals(defendantDetail.getSex())) {
                                    sex = "2";
                                }
                                defendant.setSex(sex);
                                defendant.setAddress(defendantDetail.getAddress());
                            } else if ("法人".equals(type)) {
                                defendant.setType(1);
                                defendant.setIdCard(defendantDetail.getCreditCode());
                                defendant.setAddress(defendantDetail.getCompanyAddress());
                                defendant.setLegalPersonName(defendantDetail.getLegalPerson());
                            }
                            defendantService.getSuperManager().updateById(defendant);
                        }
                    }
                }

                Matcher defendantAgentMatcher = ComplaintCaseConstant.DEFENDANT_AGENT_PATTERN.matcher(aiResult);
                while (defendantAgentMatcher.find()) {
                    String match = defendantAgentMatcher.group(1);
                    log.info("被告代理人信息:{}", match);
                    if (StringUtils.isBlank(match)) {
                        break;
                    }
                    List<AiDefendantAgentResultVO> list = JSON.parseArray(match, AiDefendantAgentResultVO.class);
                    for (AiDefendantAgentResultVO aiDefendantAgentResultVO : list) {
                        Integer i = aiDefendantAgentResultVO.getIndex();
                        String defendantAgentName = aiDefendantAgentResultVO.getName();
                        String defendantAgentInfo = aiDefendantAgentResultVO.getInfo();
                        AiDefendantAgentResultVO.DefendantDetail defendantDetail = aiDefendantAgentResultVO.getDefendantDetail();
                        //解析原告代理人信息
                        if (CollectionUtils.size(defendantAgentResultVOList) > i
                                && Objects.nonNull(i) && StringUtils.isNotBlank(defendantAgentName)) {
                            AgentResultVO agentResultVO = defendantAgentResultVOList.get(i);
                            Agent defendantAgent = new Agent();
                            defendantAgent.setId(agentResultVO.getId());
                            defendantAgent.setName(defendantAgentName);
                            defendantAgent.setSummarizeInfo(defendantAgentInfo);
                            defendantAgent.setType(0);
                            defendantAgent.setIdCard(defendantDetail.getIdCardNo());
                            if (StringUtils.isNotBlank(defendantDetail.getBirthday())) {
                                defendantAgent.setBirthDate(DateUtil.parse(defendantDetail.getBirthday(), DatePattern.PURE_DATE_FORMAT).toLocalDateTime().toLocalDate());
                            }
                            String sex = null;
                            if ("男".equals(defendantDetail.getSex())) {
                                sex = "1";
                            } else if ("女".equals(defendantDetail.getSex())) {
                                sex = "2";
                            }
                            defendantAgent.setSex(sex);
                            defendantAgent.setAddress(defendantDetail.getAddress());
                            agentService.getSuperManager().updateById(defendantAgent);
                        }
                    }
                }

                Matcher evidenceMatcher = ComplaintCaseConstant.EVIDENCE_PATTERN.matcher(aiResult);
                while (evidenceMatcher.find()) {
                    String match = evidenceMatcher.group(1);
                    log.info("证据分组信息:{}", match);
                    List<JSONObject> list = JSON.parseArray(match, JSONObject.class);
                    for (JSONObject jsonObject : list) {
                        //证据分组
                        String componentName = jsonObject.getString("分组名称");
                        String evidenceContent = jsonObject.getString("证明内容");
                        if (StringUtils.isNotBlank(componentName)) {
                            EvidenceResultVO evidenceResultVO = caseResultVO.getEvidenceResultVOList().stream().filter(vo ->
                                    vo.getComponentName().equals(componentName)
                            ).findFirst().orElse(null);
                            if (evidenceResultVO != null) {
                                EvidenceCaseRel evidenceCaseRel = new EvidenceCaseRel();
                                evidenceCaseRel.setId(evidenceResultVO.getEvidenceCaseRelId());
                                evidenceCaseRel.setSummarizeInfo(evidenceContent);
                                evidenceCaseRelService.getSuperManager().updateById(evidenceCaseRel);
                            }
                        }
                    }
                }

                Matcher caseMarkdownMatcher = ComplaintCaseConstant.CASE_MARKDOWN.matcher(aiResult);
                String complaintContent = null;
                ComplaintContentVO complaintContentVO = null;
                while (caseMarkdownMatcher.find()) {
                    complaintContent = caseMarkdownMatcher.group(1);
                    log.info("诉讼状信息:{}", complaintContent);
                    complaintContentVO = JSON.parseObject(complaintContent, ComplaintContentVO.class);
                    isSuccess = true;
                }
                if (Objects.nonNull(complaintContentVO) && isSuccess && distributedLock.lock(redisKey, 3, 3000L)) {
                    Case caseEntity = superManager.getById(caseResultVO.getId());
                    //if (Objects.nonNull(caseEntity) && Objects.isNull(caseEntity.getLastGenerateTime())) {
                    //    //第一次生成起诉书成功时请求扣费
                    //    BigDecimal bizPrice = defTenantService.getPriceByCaseTypeTenantId(caseResultVO.getBizType(), ContextUtil.getTenantId());
                    //    AccountPrepayment accountPrepayment = accountPrepaymentService.getByTenantId(ContextUtil.getTenantId());
                    //    AccountPrepaymentParamVO paramVO = new AccountPrepaymentParamVO();
                    //    paramVO.setCaseId(caseResultVO.getId());
                    //    paramVO.setId(accountPrepayment.getId());
                    //    paramVO.setAmount(bizPrice);
                    //    paramVO.setCaseName(caseResultVO.getCaseName());
                    //    paramVO.setTransferTypeEnum(TransferTypeEnum.CONSUME);
                    //    log.info("请求扣费:{}", JSON.toJSONString(paramVO));
                    //    accountPrepaymentService.deduction(paramVO);
                    //    log.info("扣费成功:{}", caseResultVO.getCaseName());
                    //}
                    String caseRemark = null;
                    String plaintffName = CollectionUtils.isNotEmpty(plaintffList) ? String.join(StrUtil.COMMA, plaintffList) : null;
                    String defendantName = CollectionUtils.isNotEmpty(defendantList) ? String.join(StrUtil.COMMA, defendantList) : null;
                    String caseType = caseEntity.getCaseType();
                    String caseTypeName = defDictManager.findDictItemByKey(EchoDictType.System.CASE_TYPE, caseType);
                    if (StrUtil.isAllNotBlank(plaintffName, defendantName, caseTypeName)) {
                        caseRemark = plaintffName + "诉" + defendantName + caseTypeName + "一案";
                    }
                    String courtName = complaintContentVO.getCourtName();
                    String city = complaintContentVO.getCity();

                    log.info("大模型返回数据，法院名称:{}，案件管辖市:{}, 原告所在市:{}, 原告所在省:{}", courtName, city, plaintffCity, plaintffProvince);
                    //查询法院地区，先精确匹配再模糊查找，再通过市匹配
                    //1、精确匹配
                    CourtArea courtArea = courtAreaService.getByCourtName(courtName);
                    if (Objects.isNull(courtArea)) {
                        //2、模糊匹配
                        List<CourtArea> courtAreas = courtAreaService.queryByCourtName(courtName);
                        //3、案件管辖市匹配
                        if (CollectionUtil.isEmpty(courtAreas) && StringUtils.isNotBlank(city)) {
                            List<DefArea> areaList = defAreaService.findByName(city);
                            if (CollectionUtils.isNotEmpty(areaList)) {
                                Long areaId = areaList.get(0).getId();
                                courtAreas = courtAreaService.queryByAreaId(areaId);
                            }
                        }
                        //4、原告市匹配
                        if (CollectionUtil.isEmpty(courtAreas) && StringUtils.isNotBlank(plaintffCity)) {
                            List<DefArea> areaList = defAreaService.findByName(plaintffCity);
                            if (CollectionUtils.isNotEmpty(areaList)) {
                                Long areaId = areaList.get(0).getId();
                                courtAreas = courtAreaService.queryByAreaId(areaId);
                            }
                        }
                        //5、原告省匹配
                        if (CollectionUtil.isEmpty(courtAreas) && StringUtils.isNotBlank(plaintffProvince)) {
                            List<DefArea> areaList = defAreaService.findByName(plaintffProvince);
                            if (CollectionUtils.isNotEmpty(areaList)) {
                                Long areaId = areaList.get(0).getId();
                                courtAreas = courtAreaService.queryByAreaId(areaId);
                            }
                        }
                        //有匹配到取匹配法院
                        if (CollectionUtils.isNotEmpty(courtAreas)) {
                            courtArea = courtAreas.get(0);
                        }
                    }

                    Case caseUpdate = new Case();
                    caseUpdate.setId(caseEntity.getId());
                    caseUpdate.setCaseRemark(caseRemark);
                    caseUpdate.setCaseState(BizConstant.CASE_STATE_SUCCESS_10);
                    caseUpdate.setComplaintContent(JSON.toJSONString(complaintContentVO));
                    caseUpdate.setClickNum(caseEntity.getClickNum() + 1);
                    caseUpdate.setLastGenerateTime(LocalDateTime.now());
                    caseUpdate.setCourtName(Objects.nonNull(courtArea) ? courtArea.getCourtName() : courtName);
                    caseUpdate.setCaseAmount(NumberUtil.isNumber(complaintContentVO.getBdje())
                            ? new BigDecimal(complaintContentVO.getBdje()) : null);
                    superManager.updateById(caseUpdate);

                    CaseLog caseLog = new CaseLog();
                    caseLog.setCaseId(caseResultVO.getId());
                    caseLog.setStatus(BizConstant.CASE_LOG_SUCCESS);
                    caseLog.setPlaintff(CollectionUtil.join(plaintffList, ","));
                    caseLog.setDefendant(CollectionUtil.join(defendantList, ","));
                    caseLog.setComplaintContent(complaintContent);
                    caseLogManager.save(caseLog);
                }
            } catch (Exception e) {
                log.error("调用AI失败", e);
                isSuccess = false;
            } finally {
                if (!isSuccess) {
                    this.updateCaseStatus(caseResultVO.getId(), BizConstant.CASE_STATE_FAIL_20);
                    CaseLog caseLog = new CaseLog();
                    caseLog.setCaseId(caseResultVO.getId());
                    caseLog.setStatus(BizConstant.CASE_LOG_FAIL);
                    caseLogManager.save(caseLog);
                }
                distributedLock.releaseLock(redisKey);
            }
        });
    }

    private void validAccountBalance(String bizType) {
        BigDecimal bizPrice = defTenantService.getPriceByCaseTypeTenantId(bizType, ContextUtil.getTenantId());
        if (Objects.isNull(bizPrice)) {
            throw new BizException("未配置案件单价，扣费失败");
        }
        AccountPrepayment accountPrepayment = accountPrepaymentService.getByTenantId(ContextUtil.getTenantId());
        if (Objects.isNull(accountPrepayment) || accountPrepayment.getBalance().compareTo(bizPrice) < 0) {
            throw new BizException("账户余额不足");
        }
    }

    @Override
    public void enableCallAi(CaseSaveVO caseSaveVO) {
        //1、校验参数
        validSaveVO(caseSaveVO);
        //2、账户余额是否充足
        //this.validAccountBalance(caseSaveVO.getBizType());
    }

    @Override
    public void enableCallAi(CaseUpdateVO caseUpdateVO) {
        //1、校验参数
        validUpdateVO(caseUpdateVO);
        //2、校验生成次数
        validClickNum(caseUpdateVO.getId());
        //3、账户余额是否充足
        //this.validAccountBalance(caseUpdateVO.getBizType());
    }

    @Override
    public void enableCallAi(CaseResultVO caseResultVO) {
        //1、校验参数
        validCaseVO(caseResultVO);
        //2、校验生成次数
        validClickNum(caseResultVO.getId());
    }

    @Override
    public boolean enableUpdate(Long caseId) {
        Case caseEntity = this.superManager.getById(caseId);
        //已生成起诉状和生成中，不能编辑
        if (Objects.nonNull(caseEntity.getLastGenerateTime())
                || BizConstant.CASE_STATE_DOING_05.equals(caseEntity.getCaseState())) {
            return false;
        }
        return true;
    }

    @Override
    public boolean updateComplaintContent(CaseUpdateComplaintContentVO caseUpdateComplaintContentVO) {
        Long caseId = caseUpdateComplaintContentVO.getId();
        String key = caseUpdateComplaintContentVO.getKey();
        String value = caseUpdateComplaintContentVO.getValue();
        log.info("修改起诉状信息:{}", caseId, JSON.toJSONString(caseUpdateComplaintContentVO));
        Case caseEntity = superManager.getById(caseId);
        if (Objects.nonNull(caseEntity)) {
            ArgumentAssert.notNull(caseEntity.getLastGenerateTime(), "起诉状未生成，无法修改");
            String complaintContent = caseEntity.getComplaintContent();
            LinkedHashMap<String, String> linkedHashMap = JSON.parseObject(complaintContent, LinkedHashMap.class);
            linkedHashMap.put(key, value);
            String courtName = linkedHashMap.get("法院");
            Case updateCase = new Case();
            updateCase.setId(caseId);
            updateCase.setComplaintContent(JSON.toJSONString(linkedHashMap));
            updateCase.setCourtName(Objects.nonNull(courtName) ? courtName : null);
            return superManager.updateById(updateCase);
        }
        return false;
    }

    @Override
    public boolean updateCaseStatus(Long caseId, String status) {
        Case caseEntity = new Case();
        caseEntity.setId(caseId);
        caseEntity.setCaseState(status);
        return superManager.updateById(caseEntity);
    }

    @Transactional
    @Override
    public boolean updateCaseShareUserId(String phone, Long userId) {
//        List<Case> caseList = superManager.listByPhone(phone);
//        if (Objects.nonNull(userId) && CollectionUtil.isNotEmpty(caseList)) {
//            caseList.forEach(caseEntity -> {
//                Case updateEntity = new Case();
//                updateEntity.setId(caseEntity.getId());
//                updateEntity.setUserId(userId);
//                superManager.updateById(updateEntity);
//
//            });
//        }
        if (StringUtils.isNotBlank(phone) && Objects.nonNull(userId)) {
            superManager.updateUserIdByPhone(userId, phone);
        }
        return true;
    }

    @Override
    public ShareInfoResultVO createShareLink(Long caseId, String phone) {
        //租户自己的移动端配置
        DefTenantAppConfig tenantAppConfig = defTenantAppConfigService.getByTenantId();
        String appId = tenantAppConfig.getAppId();
        Long mpQrcodeUrlBizId = tenantAppConfig.getId();
        //米尺律云的移动端配置
        DefTenantAppConfig adminAppConfig = defTenantAppConfigService.getAdminAppConfig();
        //租户移动端H5配置未开启，取米尺律云的配置
        if (!Objects.equals(StateEnum.ENABLE.getInteger(), tenantAppConfig.getH5State())) {
            appId = adminAppConfig.getAppId();
            mpQrcodeUrlBizId = adminAppConfig.getId();
        }
        Case caseEntity = superManager.getById(caseId);
        if (Objects.nonNull(caseEntity)) {
            DefUser defUser = defUserService.getUserByMobile(phone);
            Case updateEntity = new Case();
            updateEntity.setId(caseId);
            updateEntity.setShareTel(phone);
            updateEntity.setUserId(Objects.nonNull(defUser) ? defUser.getId() : null);
            updateEntity.setSharerUserId(ContextUtil.getUserId());
            updateEntity.setAppId(appId);
            superManager.updateById(updateEntity);
        }
        String prefixUrl = "";
        Map<String, String> paramMapByKey = defParameterManager.findParamMapByKey(Lists.newArrayList(BizConstant.SHARE_LINK_PREFIX));
        if (MapUtils.isNotEmpty(paramMapByKey)) {
            prefixUrl = paramMapByKey.getOrDefault(BizConstant.SHARE_LINK_PREFIX, "");
        }
        String url = String.format("%s?appId=%s", prefixUrl, appId);
        AppendixResultVO appendixResultVO = appendixService.getByBiz(mpQrcodeUrlBizId, AppendixType.System.DEF__MP__LOGO);
        String mpQrCodeUrl = null;
        if (Objects.nonNull(appendixResultVO)) {
            File file = fileService.getById(appendixResultVO.getId());
            mpQrCodeUrl = Objects.nonNull(file) ? file.getUrl() : null;
        }
        ShareInfoResultVO shareInfoResultVO = ShareInfoResultVO.builder().url(url).mpQrCodeUrl(mpQrCodeUrl).build();
        return shareInfoResultVO;
    }

    @Override
    public Boolean sendEmail(CaseSendEmailVO caseSendEmailVO, SysUser sysUser) {
        CaseResultVO caseResultVO = this.getCaseById(caseSendEmailVO.getId());
        if (!BizConstant.CASE_STATE_SUCCESS_10.equals(caseResultVO.getCaseState())) {
            throw new BizException("案件未完成，无法下载");
        }
        //上传文件
        String caseZipUrl;
        try {
            caseZipUrl = pdfCommonService.uploadCaseZip(caseResultVO);
            log.info("案件压缩包:{}", caseZipUrl);
        } catch (Exception e) {
            log.error("生成案件压缩包失败:", e);
            throw new BizException("邮件发送失败");
        }
        //发送邮件
        ExtendMsgSendVO data = new ExtendMsgSendVO();
        data.setCode("EMAIL_CASE_FILE");
        ExtendMsgRecipientSaveVO recipientSaveVO = ExtendMsgRecipientSaveVO.builder()
                .recipient(caseSendEmailVO.getEmail())
                .build();
        data.setRecipientList(Lists.newArrayList(recipientSaveVO));
        String title = caseResultVO.getCaseName() + "立案材料";
        data.addParam(BizConstant.MAIL_TITLE, title);
        data.addParam(BizConstant.MAIL_CASE_NAME, caseResultVO.getCaseName());
        data.addParam(BizConstant.MAIL_ATTACH_FILE_NAME, title + ".zip");
        data.addParam(BizConstant.MAIL_ATTACH_FILE_URL, caseZipUrl);
        return msgBiz.sendByTemplate(data, sysUser);
    }

    @Override
    public boolean isH5Req() {
        String clientId = ContextUtil.getClientId();
        Long tenantId = ContextUtil.getTenantId();
        boolean specialTenantId = false;
        Map<String, String> specialTenantIdsParams = defParameterManager.findParamMapByKey(Lists.newArrayList(BizConstant.SPECIAL_TENANT_IDS));
        if (MapUtils.isNotEmpty(specialTenantIdsParams)) {
            String specialTenantIds = specialTenantIdsParams.getOrDefault(BizConstant.SPECIAL_TENANT_IDS, "");
            specialTenantId = StrUtil.split(specialTenantIds, ",").contains(tenantId.toString());
        }
        return ContextConstants.DEF_CLIENT_ID.equals(clientId) && !specialTenantId;
    }

    @Override
    public String getCaseState(Long caseId) {
        Case caseEntity = superManager.getById(caseId);
        ArgumentAssert.notNull(caseEntity, "案件ID不存在");
        return caseEntity.getCaseState();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public FileResultVO upload(MultipartFile file, CaseFileUploadVO caseFileUploadVO) {
        if (!AppendixType.Complaint.COMPLAINT__SUIT__FILE.equals(caseFileUploadVO.getBizType())
                && !AppendixType.Complaint.COMPLAINT__EVIDENCE__SIGN__FILE.equals(caseFileUploadVO.getBizType())
                && !AppendixType.Complaint.COMPLAINT__IDENTITY__MATERIAL.equals(caseFileUploadVO.getBizType())
                && !AppendixType.Complaint.COMPLAINT__DELIVERY__ADDRESS__SIGN__FILE.equals(caseFileUploadVO.getBizType())
                && !AppendixType.Complaint.COMPLAINT__SETTLE_CONFIRM__SIGN__FILE.equals(caseFileUploadVO.getBizType())
                && !AppendixType.Complaint.COMPLAINT__OTHER__FILE.equals(caseFileUploadVO.getBizType())
        ) {
            throw new BizException("bizType【" + caseFileUploadVO.getBizType() + "】不支持");
        }
        FileUploadVO fileUploadVO = new FileUploadVO();
        fileUploadVO.setBizType(caseFileUploadVO.getBizType());
        FileResultVO fileResultVO = fileService.upload(file, fileUploadVO);
        String bizType = fileUploadVO.getBizType();
        Long fileId = fileResultVO.getId();
        AppendixSaveVO appendixSaveVO = AppendixSaveVO.build(caseFileUploadVO.getCaseId(), bizType, fileId, 0, null, null);
        appendixService.add(appendixSaveVO);
        return fileResultVO;
    }

    @Override
    public Boolean deleteSignatureFile(List<Long> fileIds) {
        return appendixService.removeByIds(fileIds);
    }
}


